package org.dromara.easytl.parser;

import org.dromara.easytl.exception.TemplateSyntaxException;

import java.io.IOException;

/**
 * Token 流，提供流式的 Token 读取和预览功能
 *
 * @author EasyTL Team
 */
public class TokenStream {

    private static final int DEFAULT_BUFFER_SIZE = 3;

    private final Lexer lexer;
    private final Token[] buffer;
    private int bufferSize;
    private int head;
    private boolean eof;

    public TokenStream(Lexer lexer) {
        this(lexer, DEFAULT_BUFFER_SIZE);
    }

    public TokenStream(Lexer lexer, int bufferSize) {
        this.lexer = lexer;
        this.buffer = new Token[bufferSize];
        this.bufferSize = 0;
        this.head = 0;
        this.eof = false;
    }

    /**
     * 读取下一个 Token（消费）
     *
     * @return 下一个 Token，如果到达末尾返回 EOF Token
     */
    public Token nextToken() {
        try {
            ensureBuffer(1);
            if (bufferSize == 0) {
                return createEOFToken();
            }
            Token token = buffer[head];
            head = (head + 1) % buffer.length;
            bufferSize--;
            return token;
        } catch (IOException e) {
            throw new TemplateSyntaxException("读取 Token 时发生错误", e);
        }
    }

    /**
     * 预览下一个 Token（不消费）
     *
     * @return 下一个 Token，如果到达末尾返回 EOF Token
     */
    public Token peek() {
        return peek(0);
    }

    /**
     * 预览指定偏移位置的 Token（不消费）
     *
     * @param offset 偏移量（0 表示下一个 Token）
     * @return 指定位置的 Token，如果超出范围返回 EOF Token
     */
    public Token peek(int offset) {
        try {
            ensureBuffer(offset + 1);
            if (offset >= bufferSize) {
                return createEOFToken();
            }
            int index = (head + offset) % buffer.length;
            return buffer[index];
        } catch (IOException e) {
            throw new TemplateSyntaxException("预览 Token 时发生错误", e);
        }
    }

    /**
     * 判断是否还有更多 Token
     *
     * @return 如果还有 Token 返回 true
     */
    public boolean hasNext() {
        try {
            ensureBuffer(1);
            return bufferSize > 0;
        } catch (IOException e) {
            return false;
        }
    }

    /**
     * 获取当前 Token 位置
     *
     * @return 当前位置
     */
    public int getPosition() {
        Token token = peek();
        return token.getPosition();
    }

    /**
     * 确保缓冲区中有足够的 Token
     *
     * @param required 需要的 Token 数量
     * @throws IOException 读取错误
     */
    private void ensureBuffer(int required) throws IOException {
        if (eof || bufferSize >= required) {
            return;
        }

        while (bufferSize < required && bufferSize < buffer.length && !eof) {
            Token token = lexer.nextToken();
            if (token.getType() == TokenType.EOF) {
                eof = true;
                break;
            }
            int tail = (head + bufferSize) % buffer.length;
            buffer[tail] = token;
            bufferSize++;
        }
    }

    /**
     * 创建 EOF Token
     */
    private Token createEOFToken() {
        return new Token(TokenType.EOF, lexer.getLine(), lexer.getColumn(), lexer.getPosition());
    }
}

